package jnpf.engine.custom.type;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jnpf.base.UserInfo;
import jnpf.base.util.SentMessageUtil;
import jnpf.config.ConfigValueUtil;
import jnpf.constant.FileTypeConstant;
import jnpf.engine.custom.behavior.impl.CustomManualTaskActivityBehavior;
import jnpf.engine.custom.cmd.commons.ExpressionCmd;
import jnpf.engine.custom.constants.BasicActivitiConstants;
import jnpf.engine.custom.helper.UserTaskNodeHelper;
import jnpf.engine.entity.FlowTaskCirculateEntity;
import jnpf.engine.entity.FlowTaskOperatorEntity;
import jnpf.engine.entity.FlowTaskOperatorRecordEntity;
import jnpf.engine.entity.FlowTemplateJsonEntity;
import jnpf.engine.enums.*;
import jnpf.engine.model.FlowTaskDTO;
import jnpf.engine.model.FlowTaskNodeDTO;
import jnpf.engine.model.FlowTaskOperatorRecordDTO;
import jnpf.engine.model.flowbefore.FlowTemplateAllModel;
import jnpf.engine.model.flowengine.FlowModel;
import jnpf.engine.model.flowengine.shuntjson.childnode.*;
import jnpf.engine.model.flowengine.shuntjson.childnode.Properties;
import jnpf.engine.model.flowengine.shuntjson.childnode.dto.MailFileInfo;
import jnpf.engine.model.flowmessage.FlowMsgModel;
import jnpf.engine.model.flowtask.FlowConditionModel;
import jnpf.engine.service.FlowTaskCirculateService;
import jnpf.engine.service.FlowTaskOperatorRecordService;
import jnpf.engine.service.FlowTemplateJsonService;
import jnpf.engine.util.*;
import jnpf.exception.WorkFlowException;
import jnpf.message.model.SentMessageForm;
import jnpf.permission.entity.OrganizeEntity;
import jnpf.permission.entity.UserEntity;
import jnpf.permission.entity.UserRelationEntity;
import jnpf.permission.service.UserRelationService;
import jnpf.permission.service.UserService;
import jnpf.util.*;
//import jnpf.util.enums.FileTypeEnum;
//import jnpf.util.file.UploadUtil;
import jnpf.util.context.SpringContext;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.engine.*;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.event.impl.FlowableActivityEventImpl;
import org.flowable.engine.impl.bpmn.behavior.ReceiveTaskActivityBehavior;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.SimpleHtmlSerializer;
import org.htmlcleaner.TagNode;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.script.ScriptEngine;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.text.ParseException;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import static jnpf.engine.custom.constants.GlobalProcessVariableConstants.*;
import static jnpf.engine.custom.constants.RootExecutionVariableConstants.*;
import static jnpf.engine.custom.constants.RootExecutionVariableConstants.MULTI_INSTANCE_NUM_ABSTENTION;
import static jnpf.engine.util.BpmnModelUtils.*;
import static jnpf.engine.util.EvalUtils.*;
import static jnpf.engine.util.EvalUtils.search;

@Component
@Slf4j
public class ActivityStartedListener implements FlowableEventListener {
    @Override
    public void onEvent(FlowableEvent event) {
        //
        ActivitiUtils activitiUtils = SpringContextHolder.getBean(ActivitiUtils.class);
        UserRelationService userRelationService = SpringContextHolder.getBean(UserRelationService.class);
        FlowTaskCirculateService flowTaskCirculateService = SpringContextHolder.getBean(FlowTaskCirculateService.class);
        SentMessageUtil sentMessageUtil = SpringContextHolder.getBean(SentMessageUtil.class);
        UserTaskNodeHelper userTaskNodeHelper = SpringContextHolder.getBean(UserTaskNodeHelper.class);

        if(event instanceof FlowableActivityEventImpl) {
            FlowableActivityEventImpl activityEvent = (FlowableActivityEventImpl) event;
            String activityId = activityEvent.getActivityId();
            String executionId = activityEvent.getExecutionId();
            String activityType = activityEvent.getActivityType();
            String behaviorClass = activityEvent.getBehaviorClass();
            String processDefinitionId = activityEvent.getProcessDefinitionId();
            String processInstanceId = activityEvent.getProcessInstanceId();
            DelegateExecution execution = activityEvent.getExecution();
            Map<String, Object> map = execution.getVariables();
            UserService usersApi = SpringContextHolder.getBean(UserService.class);
            if(ReceiveTaskActivityBehavior.class.getName().equals(behaviorClass)){
                RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
                Process process = BpmnModelUtils.getBpmnModelMainProcess(processDefinitionId);
                ReceiveTask activity = (ReceiveTask) process.getFlowElement(activityId);
                Process bpmnModelMainProcess = getBpmnModelMainProcess(execution.getProcessDefinitionId());
                String currentActivityId = execution.getCurrentActivityId();
                String receiveTaskStr = getAttributeValueByTaskDefinitionKey(bpmnModelMainProcess, currentActivityId, "receiveTask");
                jnpf.engine.model.flowengine.shuntjson.childnode.Properties properties = JSONObject.parseObject(receiveTaskStr, new TypeReference<jnpf.engine.model.flowengine.shuntjson.childnode.Properties>() {
                });
                FlowTaskUtil flowTaskUtil = SpringContextHolder.getBean(FlowTaskUtil.class);
                Properties firstNodeProperty = getFirstNodeProperty(execution.getProcessDefinitionId());
                Map<String, Object> formData = flowTaskUtil.infoData(firstNodeProperty.getFormId(), execution.getProcessInstanceBusinessKey());
                //先判断主要的
                Boolean timeModeFlag = properties.getTimeModeFlag();
                //
                if(Boolean.TRUE.equals(timeModeFlag)){
                    //延迟一段时间
                    //判断天
                    Boolean dayFieldFlag = properties.getDayFieldFlag();
                    Long totalSeconds=1L;
                    if(Boolean.TRUE.equals(dayFieldFlag)){
                        //
                        Object o = formData.get(properties.getDayField());
                        if(o!=null && o instanceof Number){
                            Number number =(Number)o;
                            long l = number.longValue();
                            totalSeconds+=TimeUtils.getSecondsByDay(l);
                        }
                    }
                    else{
                        totalSeconds+=TimeUtils.getSecondsByDay(Long.valueOf(properties.getDay()));
                    }
                    //判断小时
                    Boolean hourFieldFlag = properties.getHourFieldFlag();
                    if(Boolean.TRUE.equals(hourFieldFlag)){
                        //
                        Object o = formData.get(properties.getHourField());
                        if(o!=null && o instanceof Number){
                            Number number =(Number)o;
                            long l = number.longValue();
                            totalSeconds+=TimeUtils.getSecondsByHour(l);
                        }
                    }
                    else{
                        totalSeconds+=TimeUtils.getSecondsByHour(Long.valueOf(properties.getHour()));
                    }
                    //判断分钟
                    Boolean minuteFieldFlag = properties.getMinuteFieldFlag();
                    if(Boolean.TRUE.equals(minuteFieldFlag)){
                        //
                        Object o = formData.get(properties.getMinuteField());
                        if(o!=null && o instanceof Number){
                            Number number =(Number)o;
                            long l = number.longValue();
                            totalSeconds+=TimeUtils.getSecondsByMinute(l);
                        }
                    }
                    else{
                        totalSeconds+=TimeUtils.getSecondsByMinute(Long.valueOf(properties.getMinute()));
                    }
                    //判断秒
                    Boolean secondFieldFlag = properties.getSecondFieldFlag();
                    if(Boolean.TRUE.equals(secondFieldFlag)){
                        //
                        Object o = formData.get(properties.getMinuteField());
                        if(o!=null && o instanceof Number){
                            Number number =(Number)o;
                            long l = number.longValue();
                            totalSeconds+= l;
                        }
                    }
                    else{
                        totalSeconds+=properties.getSecond();
                    }
                    String key=BasicActivitiConstants.RECEIVE_TASK_TIME_KEY_PREFIX+"-"+processInstanceId+"-"+executionId+"-"+activityId;
                    //
                    redisUtil.insert(key,true,totalSeconds);
                }
                else{
                    //
                    Boolean pointDateFlag = properties.getPointDateFlag();
                    Date date=null;
                    if(Boolean.TRUE.equals(pointDateFlag)){
                        //
                        String pointDateField = properties.getPointDateField();
                        Object o = formData.get(pointDateField);
                        //
                        if(o instanceof Long){
                            //
                            date=new Date((Long) o);
                        }
                    }
                    else{
                        //
                        String pointDate = properties.getPointDate();
                        //
                        date=new Date(Long.valueOf(pointDate));
                    }

                    if(date!=null){
                        LocalDateTime localDate = TimeUtils.date2LocalDate(date);
                        String pointDateMode = properties.getPointDateMode();
                        //
                        if("1".equals(pointDateMode)){
                                //
                            String pointTimePicker = properties.getPointTimePicker();
                                Date toDate = new Date(Long.valueOf(pointTimePicker));
                                LocalDateTime localDateTime = TimeUtils.date2LocalDate(toDate);
                                int hour = localDateTime.getHour();
                                int minute = localDateTime.getMinute();
                                int second = localDateTime.getSecond();
                                localDateTime = localDate.withHour(hour).withMinute(minute).withSecond(second);
                                LocalDateTime now = LocalDateTime.now();
                                Duration between = Duration.between(now, localDateTime);
                                long seconds = between.getSeconds();
                            String key=BasicActivitiConstants.RECEIVE_TASK_TIME_KEY_PREFIX+"-"+processInstanceId+"-"+executionId+"-"+activityId;
                                if(seconds>0){
                                    redisUtil.insert(key,true,seconds);
                                }
                                else{
                                    redisUtil.insert(key,true,1);
                                }
                        }
                        else if("2".equals(pointDateMode)){
                            String pointTimePicker = properties.getPointTimePicker();
                            //之前
                            Date toDate = new Date(Long.valueOf(pointTimePicker));
                            LocalDateTime localDateTime = TimeUtils.date2LocalDate(toDate);
                            int hour = localDateTime.getHour();
                            int minute = localDateTime.getMinute();
                            int second = localDateTime.getSecond();
                            localDateTime = localDate.withHour(hour).withMinute(minute).withSecond(second);
                            LocalDateTime now = LocalDateTime.now();

                            //
                            Integer pointDays = properties.getPointDays();
                            localDateTime = localDateTime.minusDays(pointDays);
                            Duration between = Duration.between(now, localDateTime);
                            long seconds = between.getSeconds();
                            String key=BasicActivitiConstants.RECEIVE_TASK_TIME_KEY_PREFIX+"-"+processInstanceId+"-"+executionId+"-"+activityId;
                            if(seconds>0){
                                redisUtil.insert(key,true,seconds);
                            }
                            else{
                                redisUtil.insert(key,true,1);
                            }
                        }
                        //之后
                        else if("3".equals(pointDateMode)){
                            String pointTimePicker = properties.getPointTimePicker();
                            //之前
                            Date toDate = new Date(Long.valueOf(pointTimePicker));
                            LocalDateTime localDateTime = TimeUtils.date2LocalDate(toDate);
                            int hour = localDateTime.getHour();
                            int minute = localDateTime.getMinute();
                            int second = localDateTime.getSecond();
                            localDateTime = localDate.withHour(hour).withMinute(minute).withSecond(second);
                            LocalDateTime now = LocalDateTime.now();

                            //
                            Integer pointDays = properties.getPointDays();
                            localDateTime = localDateTime.plusDays(pointDays);
                            Duration between = Duration.between(now, localDateTime);
                            long seconds = between.getSeconds();
                            String key=BasicActivitiConstants.RECEIVE_TASK_TIME_KEY_PREFIX+"-"+processInstanceId+"-"+executionId+"-"+activityId;
                            if(seconds>0){
                                redisUtil.insert(key,true,seconds);
                            }
                            else{
                                redisUtil.insert(key,true,1);
                            }
                        }
                    }
                }


//                Integer totalSeconds = properties.getTotalSeconds();
//                if(totalSeconds!=null){
//                    String key=BasicActivitiConstants.RECEIVE_TASK_TIME_KEY_PREFIX+"-"+processInstanceId+"-"+executionId+"-"+activityId;
//                    //
//                    redisUtil.insert(key,true,totalSeconds);
//                }


            }
            else if(CustomManualTaskActivityBehavior.class.getName().equals(behaviorClass)) {
                ServiceAllUtil serviceAllUtil = SpringContextHolder.getBean(ServiceAllUtil.class);
                FlowTaskCirculateService circulateService = SpringContextHolder.getBean(FlowTaskCirculateService.class);
                FlowTemplateJsonService flowTemplateJsonService = SpringContextHolder.getBean(FlowTemplateJsonService.class);
                FlowMsgUtil flowMsgUtil = SpringContextHolder.getBean(FlowMsgUtil.class);
                FlowTaskUtil flowTaskUtil = SpringContextHolder.getBean(FlowTaskUtil.class);
                String dirProp = System.getProperty("user.dir");
                Process process = BpmnModelUtils.getBpmnModelMainProcess(processDefinitionId);
                ManualTask activity = (ManualTask) process.getFlowElement(activityId);
                String manualTaskStr = getAttributeValueByTaskDefinitionKey(process, activity.getId(), "manualTask");
                Properties properties = JSONObject.parseObject(manualTaskStr, new TypeReference<Properties>() {
                });
                String nodeType = properties.getNodeType();
                if (FlowNodeTypeEnum.COPY.getType().equals(nodeType)) {
                    List<String> userIdAll = new ArrayList<>();
                    userIdAll.addAll(properties.getCirculateUser());
                    List<String> userListAll = serviceAllUtil.getUserListAll(userIdAll);
                    userIdAll.addAll(userListAll);
                    String applyUserId = MapUtil.getStr(map, APPLY_USER_ID);
                    //附加规则
                    UserTaskNodeHelper.rule(userIdAll, applyUserId, properties.getExtraCopyRule());
                    //获取最新用户
                    List<UserEntity> userList = serviceAllUtil.getUserName(userIdAll, true);
                    UserTask firstUserTaskNode = getFirstUserTaskNode(processDefinitionId);
                    HistoryService historyService = SpringContextHolder.getBean(HistoryService.class);
                    String id = firstUserTaskNode.getId();
                    HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(execution.getProcessInstanceId()).taskDefinitionKey(id).listPage(0, 1).get(0);
                    List<FlowTaskCirculateEntity> flowTaskCirculateEntities= new ArrayList<>();
                    UserService userService = SpringContextHolder.getBean(UserService.class);
                    UserEntity userServiceInfo = userService.getInfo(applyUserId);
                    for (UserEntity userEntity : userList) {
                        FlowTaskCirculateEntity circulate = new FlowTaskCirculateEntity();
                        circulate.setId(RandomUtil.uuId());
                        circulate.setObjectId(userEntity.getId());
                        circulate.setNodeCode(firstUserTaskNode.getId());
                        circulate.setNodeName(properties.getTitle());
//                        circulate.setTaskNodeId(taskId);
                        circulate.setTaskId(processInstanceId);
                        circulate.setEnCode(MapUtil.getStr(map,BILL_CODE));
                        circulate.setFullName(MapUtil.getStr(map,BUSINESS_TITLE));
                        circulate.setTemplateId(MapUtil.getStr(map,FLOW_ENGINE_ID));
                        circulate.setFlowId(MapUtil.getStr(map,FLOW_TEMPLATE_JSON_ID));
                        circulate.setFlowCategory(MapUtil.getStr(map,PROCESS_CATEGORY));
                        circulate.setFlowUrgent(MapUtil.getInt(map,FLOW_URGENT));
                        circulate.setCreatorTime(new Date());
                        circulate.setApplyUserId(userServiceInfo.getRealName()+"/"+userServiceInfo.getAccount());
                        circulate.setApplyUserIdReal(userServiceInfo.getId());
                        circulate.setTaskNodeId(historicTaskInstance.getId());
                        circulate.setProcessStatus(MapUtil.getInt(map,PROCESS_STATUS));
                        flowTaskCirculateEntities.add(circulate);
                    }
                    circulateService.saveBatch(flowTaskCirculateEntities);
                    Properties firstNodeProperty = getFirstNodeProperty(processDefinitionId);
                    MsgConfig copyMsgConfig = firstNodeProperty.getCopyMsgConfig();
                    Integer on = copyMsgConfig.getOn();
                    Boolean messageFlag=false;
                    if(on!=0){
                        messageFlag=true;
                    }

                    if(messageFlag){

                        Map<String, Object> variables = execution.getVariables();
                        Integer processStatus = MapUtil.getInt(variables, PROCESS_STATUS);
                        String businessTitle = MapUtil.getStr(variables, BUSINESS_TITLE);
                        LambdaQueryWrapper<FlowTemplateJsonEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                        lambdaQueryWrapper.eq(FlowTemplateJsonEntity::getProcessDefinitionId,processDefinitionId);
                        lambdaQueryWrapper.select(FlowTemplateJsonEntity::getId);
                        FlowTemplateJsonEntity flowTemplateJsonEntity = flowTemplateJsonService.getOne(lambdaQueryWrapper);
                        FlowTemplateAllModel templateAllModel = flowTaskUtil.templateJson(flowTemplateJsonEntity.getId());
                        FlowMsgModel flowMsgModel = new FlowMsgModel();
                        if(CollUtil.isNotEmpty(flowTaskCirculateEntities)){
                            flowMsgModel.setCirculateList(flowTaskCirculateEntities);
                            flowMsgModel.setCopy(Boolean.TRUE);
                        }
                        flowMsgModel.setStartNodeProperties(firstNodeProperty);
                        flowMsgModel.setCurrentNodeProperties(firstNodeProperty);
//                    flowMsgModel.setNodeList(taskNodeList);
                        List<FlowTaskOperatorEntity> operatorEntityList = new ArrayList<>();
//                        operatorEntityList.add(operator);
//                        flowMsgModel.setOperatorList(operatorEntityList);
                        flowMsgModel.setData(map);
//                    flowMsgModel.setFlowModel(flowModel);
                        FlowTaskDTO flowTask = new FlowTaskDTO();
                        flowTask.setCreatorUserId(applyUserId);
                        flowTask.setStatus(processStatus);
                        flowTask.setFullName(businessTitle);
                        flowMsgModel.setTaskEntity(flowTask);

                        FlowTaskNodeDTO flowTaskNodeDTO = new FlowTaskNodeDTO();
                        flowTaskNodeDTO.setTaskId(processInstanceId);
                        flowTaskNodeDTO.setTaskNodeId(historicTaskInstance.getId());
                        flowMsgModel.setTaskNodeEntity(flowTaskNodeDTO);
                        FlowModel flowModel  = new FlowModel();
                        flowModel.setUserInfo(UserProvider.getUser());
                        flowMsgModel.setFlowModel(flowModel);
                        flowMsgModel.setFlowTemplateAllModel(templateAllModel);
                        flowMsgModel.setTaskId(execution.getProcessInstanceId());
                        flowMsgModel.setTaskNodeId(historicTaskInstance.getId());
                        flowMsgUtil.message(flowMsgModel);
                    }
                }
                else if(FlowNodeTypeEnum.MAIL.getType().equals(nodeType)){

                    JavaMailSender javaMailSender = SpringContextHolder.getBean(JavaMailSender.class);
                    ConfigValueUtil configValueUtil = SpringContextHolder.getBean(ConfigValueUtil.class);
                    MimeMessage mimeMessage = javaMailSender.createMimeMessage();
                    MimeMessageHelper helper= null;
                    try {
                        helper = new MimeMessageHelper(mimeMessage,true, Constants.UTF8);
                    } catch (MessagingException e) {
                        e.printStackTrace();
                        throw new WorkFlowException("发送邮件失败");
                    }


                    List<String> to = properties.getTo();
                    String from = properties.getFrom();
                    List<String> cc = properties.getCc();
                    List<String> bcc = properties.getBcc();
                    String subject = properties.getSubject();
                    String html = properties.getHtml();
                    List<MailFileInfo> mailFiles = properties.getMailFiles();


                    Set<String> userIds=new HashSet<>();
                    userIds.addAll(to);
                    userIds.addAll(cc);
                    userIds.addAll(bcc);


                    //
                    if(CollUtil.isNotEmpty(userIds)){
                        LambdaQueryWrapper<UserEntity> userEntityQueryWrapper=new LambdaQueryWrapper<>();
                        userEntityQueryWrapper.in(UserEntity::getId,userIds);
                        List<UserEntity> list = usersApi.list(userEntityQueryWrapper);

                        List<String> emailTo=new ArrayList<>();
                        List<String> emailCc=new ArrayList<>();
                        List<String> emailBcc=new ArrayList<>();

                        for (UserEntity userEntity : list) {
                            String email = userEntity.getEmail();
                            String id = userEntity.getId();
                            if(StringUtils.isNotBlank(email)){
                                if(to.contains(id)){
                                    emailTo.add(email);
                                }
                                else if(cc.contains(id)){
                                    emailCc.add(email);
                                }
                                else if(bcc.contains(id)){
                                    emailBcc.add(id);
                                }
                            }
                        }

                        if(emailTo.isEmpty() && emailCc.isEmpty() && emailBcc.isEmpty()){
                            return;
                        }

                        List<File> fileList=new ArrayList<>();
                        try{

                            helper.setFrom("2471089198@qq.com");
                            if(!emailTo.isEmpty()){
                                helper.setTo(emailTo.toArray(new String[emailTo.size()]));
                            }
                            if(!emailCc.isEmpty()){
                                helper.setCc(emailCc.toArray(new String[emailCc.size()]));
                            }
                            if(emailBcc.isEmpty()){
                                helper.setBcc(emailBcc.toArray(new String[emailBcc.size()]));
                            }
                            helper.setSubject(subject);
                            HtmlCleaner htmlCleaner=new HtmlCleaner();
                            TagNode tagNode = htmlCleaner.clean(html);
                            Object[] objects = tagNode.evaluateXPath("//img");
                            List<Object> elements = Arrays.asList(objects);
                            Map<String, File> fileMap=new HashMap<>();

                            fileList=new ArrayList<>();

                            for (Object element : elements) {
                                TagNode imgTagNode=(TagNode)element;
                                String src = imgTagNode.getAttributeByName("src");
                                String base64=";base64,";
                                String data="data:image/";
                                int i = src.indexOf(base64);
                                String suffix = src.substring(data.length(), i);
                                i=i+base64.length();
                                String substring = src.substring(i, src.length() - 2);
                                byte[] decode = Base64.decode(substring);
                                String fileName = cn.hutool.core.util.RandomUtil.randomString(10);
                                File tempFile = new File( dirProp+File.separator+fileName + "." + suffix);
                                FileUtil.writeBytes(decode,tempFile);
                                Map<String,String> attr=new HashMap<>();
                                attr.put("src","cid:"+fileName);
                                imgTagNode.setAttributes(attr);
                                fileMap.put(fileName,tempFile);
                                fileList.add(tempFile);
                            }

                            SimpleHtmlSerializer serializer = new SimpleHtmlSerializer(htmlCleaner.getProperties());
                            File tempFile = new File(dirProp+File.separator+ cn.hutool.core.util.RandomUtil.randomString(9));
                            serializer.writeToFile(tagNode,tempFile.getAbsolutePath());
                            String finalStr = FileUtil.readString(tempFile, "UTF-8");
                            helper.setText(finalStr,true);
                            fileList.add(tempFile);
                            Set<String> set = fileMap.keySet();
                            for (String s : set) {
                                helper.addInline(s,fileMap.get(s));
                            }


                            String temporaryFile = configValueUtil.getTemporaryFilePath();
                            String mailFilePath = configValueUtil.getEmailFilePath();
                            if(mailFiles!=null){
                                for (MailFileInfo mailFile : mailFiles) {
                                    byte[] bytes = FileUploadUtils.downloadFileByte(configValueUtil.getTemporaryFilePath(), mailFile.getName(), false);
                                    FileUploadUtils.uploadFile(bytes, configValueUtil.getEmailFilePath(), mailFile.getName());
                                }

                                if (mailFiles.size() > 0) {
                                    for (MailFileInfo mailFile : mailFiles) {
                                        FileUploadUtils.downLocal(FileTypeConstant.MAIL, mailFilePath,mailFile.getName());
                                        File file = new File(mailFilePath + mailFile.getFileId());
                                        String name = mailFile.getName();
                                        helper.addAttachment(name, file);
                                    }
                                }
                            }


                            javaMailSender.send(mimeMessage);
                        }
                        catch (Exception e){
                            e.printStackTrace();
                            throw new WorkFlowException("发送邮件失败");
                        }
                        finally {
                            if(fileList.size()>0){
                                for (File file : fileList) {
                                    if(file!=null){
                                        file.delete();
                                    }
                                }
                            }
                        }


                    }
                }
                else if(FlowNodeTypeEnum.ZHAN.getType().equals(nodeType)){
                    List<String> to = properties.getTo();
                    if(CollUtil.isNotEmpty(to)){
                        List<FlowTaskCirculateEntity> flowTaskCirculateEntityList = new ArrayList<>();
                        String notifyContent = properties.getNotifyContent();
                        Boolean processFlag = properties.getProcessFlag();
                        if(processFlag){
                            List<UserEntity> userEntity = serviceAllUtil.getUserName(to);
                            Map<String,UserEntity> userEntityMap = new HashMap<>();
                            for (UserEntity entity : userEntity) {
                                userEntityMap.put(entity.getId(),entity);
                            }
                            UserService userService = SpringContextHolder.getBean(UserService.class);
                            UserEntity userServiceInfo = userService.getInfo(MapUtil.getStr(map,APPLY_USER_ID));
                            for (String userId : to) {
                                UserTask firstUserTaskNode = getFirstUserTaskNode(processDefinitionId);
                                FlowTaskCirculateEntity circulate = new FlowTaskCirculateEntity();
                                circulate.setId(RandomUtil.uuId());
                                circulate.setObjectId(userId);
                                circulate.setNodeCode(firstUserTaskNode.getId());
                                circulate.setNodeName(properties.getTitle());
//                        circulate.setTaskNodeId(taskId);
                                circulate.setTaskId(processInstanceId);
                                circulate.setEnCode(MapUtil.getStr(map,BILL_CODE));
                                circulate.setFullName(MapUtil.getStr(map,BUSINESS_TITLE));
                                circulate.setTemplateId(MapUtil.getStr(map,FLOW_ENGINE_ID));
                                circulate.setFlowId(MapUtil.getStr(map,FLOW_TEMPLATE_JSON_ID));
                                circulate.setFlowCategory(MapUtil.getStr(map,PROCESS_CATEGORY));
                                circulate.setFlowUrgent(MapUtil.getInt(map,FLOW_URGENT));
                                circulate.setCreatorTime(new Date());
                                UserEntity user = userEntityMap.get(userId);
                                circulate.setApplyUserId(userServiceInfo.getRealName()+"/"+userServiceInfo.getAccount());
                                circulate.setApplyUserIdReal(userServiceInfo.getId());
                                circulate.setProcessStatus(MapUtil.getInt(map,PROCESS_STATUS));
                            }
                            //1.传阅的批量数据插入
                            if (!flowTaskCirculateEntityList.isEmpty()) {
                                flowTaskCirculateService.create(flowTaskCirculateEntityList);
                            }
                        }



                    }

                }
                else if(FlowNodeTypeEnum.HTTP_TASK.getType().equals(nodeType)){
                    FlowTaskOperatorRecordService flowTaskOperatorRecordService = SpringContextHolder.getBean(FlowTaskOperatorRecordService.class);
                    FuncConfig httpInitFuncConfig = properties.getHttpInitFuncConfig();
                    LambdaQueryWrapper<FlowTaskOperatorRecordEntity> flowTaskOperatorRecordEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
                    flowTaskOperatorRecordEntityLambdaQueryWrapper.eq(FlowTaskOperatorRecordEntity::getTaskId,execution.getProcessInstanceId());
                    UserTask firstNode = getFirstNode(process);
                    flowTaskOperatorRecordEntityLambdaQueryWrapper.eq(FlowTaskOperatorRecordEntity::getNodeCode,firstNode.getId());
                    FlowTaskOperatorRecordEntity flowTaskOperatorRecordEntity = flowTaskOperatorRecordService.list(flowTaskOperatorRecordEntityLambdaQueryWrapper).get(0);
                    FlowModel flowModel = new FlowModel();
                    Properties applyProperties = getFirstNodeProperty(execution.getProcessDefinitionId());
                    Map<String, Object> infoData = flowTaskUtil.infoData(applyProperties.getFormId(), execution.getProcessInstanceBusinessKey());
                    flowModel.setFormData(infoData);

                    FlowTaskOperatorRecordDTO flowTaskOperatorRecordDTO = new FlowTaskOperatorRecordDTO();
                    flowTaskOperatorRecordDTO.setAssignee(flowTaskOperatorRecordEntity.getHandleId());
                    flowTaskOperatorRecordDTO.setProcessInstanceId(flowTaskOperatorRecordEntity.getTaskId());
                    flowTaskOperatorRecordDTO.setTaskId(flowTaskOperatorRecordEntity.getTaskNodeId());
                    properties.getHttpInitFuncConfig().setOn(Boolean.TRUE);
//                    ThreadPoolTaskExecutor threadPoolExecutor = SpringContext.getBean(ThreadPoolTaskExecutor.class);
//                    CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
//                        flowMsgUtil.event(10, properties, flowTaskOperatorRecordDTO, flowModel);
//                    }, threadPoolExecutor);
                    flowMsgUtil.event(10, properties, flowTaskOperatorRecordDTO, flowModel,process,activity.getId());

                }
                else if(FlowNodeTypeEnum.SQL_TASK.getType().equals(nodeType)){
                    FlowTaskOperatorRecordService flowTaskOperatorRecordService = SpringContextHolder.getBean(FlowTaskOperatorRecordService.class);
                    LambdaQueryWrapper<FlowTaskOperatorRecordEntity> flowTaskOperatorRecordEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
                    flowTaskOperatorRecordEntityLambdaQueryWrapper.eq(FlowTaskOperatorRecordEntity::getTaskId,execution.getProcessInstanceId());
                    UserTask firstNode = getFirstNode(process);
                    flowTaskOperatorRecordEntityLambdaQueryWrapper.eq(FlowTaskOperatorRecordEntity::getNodeCode,firstNode.getId());
                    FlowTaskOperatorRecordEntity flowTaskOperatorRecordEntity = flowTaskOperatorRecordService.list(flowTaskOperatorRecordEntityLambdaQueryWrapper).get(0);
                    FlowModel flowModel = new FlowModel();
                    Properties applyProperties = getFirstNodeProperty(execution.getProcessDefinitionId());
                    Map<String, Map<String, Object>> nodeFormData = FlowContextHolder.getNodeFormData();
                    Map<String,Object> dataMap = new HashMap<>();
                    Set<String> strings = nodeFormData.keySet();
                    for (String string : strings) {
                        Map<String, Object> tempMap = nodeFormData.get(string);
                        dataMap.putAll(tempMap);
                    }
                    flowModel.setFormData(dataMap);
                    FlowTaskOperatorRecordDTO flowTaskOperatorRecordDTO = new FlowTaskOperatorRecordDTO();
                    flowTaskOperatorRecordDTO.setAssignee(flowTaskOperatorRecordEntity.getHandleId());
                    flowTaskOperatorRecordDTO.setProcessInstanceId(flowTaskOperatorRecordEntity.getTaskId());
                    flowTaskOperatorRecordDTO.setTaskId(flowTaskOperatorRecordEntity.getTaskNodeId());
                    properties.getSqlInitFuncConfig().setOn(Boolean.TRUE);
                    flowMsgUtil.event(11, properties, flowTaskOperatorRecordDTO, flowModel,process,activity.getId());

                }
                else if(FlowNodeTypeEnum.MESSAGE.getType().equals(nodeType)){
                    List<String> msgUserIds = properties.getMsgUserIds();
                    List<String> userIdAll = new ArrayList<>();
                    List<String> userListAll = serviceAllUtil.getUserListAll(msgUserIds);
                    userIdAll.addAll(userListAll);
                    String applyUserId = MapUtil.getStr(map, APPLY_USER_ID);

                    UserTask firstUserTaskNode = getFirstUserTaskNode(processDefinitionId);
                    String id = firstUserTaskNode.getId();
                    List<UserEntity> userList = serviceAllUtil.getUserName(userIdAll, true);
                    List<FlowTaskCirculateEntity> flowTaskCirculateEntities= new ArrayList<>();
                    UserService userService = SpringContextHolder.getBean(UserService.class);
                    UserEntity userServiceInfo = userService.getInfo(applyUserId);
                    HistoryService historyService = SpringContextHolder.getBean(HistoryService.class);
                    HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(execution.getProcessInstanceId()).taskDefinitionKey(id).listPage(0, 1).get(0);
                    for (UserEntity userEntity : userList) {
                        FlowTaskCirculateEntity circulate = new FlowTaskCirculateEntity();
                        circulate.setId(RandomUtil.uuId());
                        circulate.setObjectId(userEntity.getId());
                        circulate.setNodeCode(firstUserTaskNode.getId());
                        circulate.setNodeName(properties.getTitle());
//                        circulate.setTaskNodeId(taskId);
                        circulate.setTaskId(processInstanceId);
                        circulate.setEnCode(MapUtil.getStr(map,BILL_CODE));
                        circulate.setFullName(MapUtil.getStr(map,BUSINESS_TITLE));
                        circulate.setTemplateId(MapUtil.getStr(map,FLOW_ENGINE_ID));
                        circulate.setFlowId(MapUtil.getStr(map,FLOW_TEMPLATE_JSON_ID));
                        circulate.setFlowCategory(MapUtil.getStr(map,PROCESS_CATEGORY));
                        circulate.setFlowUrgent(MapUtil.getInt(map,FLOW_URGENT));
                        circulate.setCreatorTime(new Date());
                        circulate.setApplyUserId(userServiceInfo.getRealName()+"/"+userServiceInfo.getAccount());
                        circulate.setApplyUserIdReal(userServiceInfo.getId());
                        circulate.setTaskNodeId(historicTaskInstance.getId());
                        circulate.setProcessStatus(MapUtil.getInt(map,PROCESS_STATUS));
                        flowTaskCirculateEntities.add(circulate);
                    }
                    circulateService.saveBatch(flowTaskCirculateEntities);

                    MsgConfig messageMsgConfig = properties.getMessageMsgConfig();
                    Map<String, Object> variables = execution.getVariables();
                    Integer processStatus = MapUtil.getInt(variables, PROCESS_STATUS);
                    String businessTitle = MapUtil.getStr(variables, BUSINESS_TITLE);
                    LambdaQueryWrapper<FlowTemplateJsonEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                    lambdaQueryWrapper.eq(FlowTemplateJsonEntity::getProcessDefinitionId,processDefinitionId);
                    lambdaQueryWrapper.select(FlowTemplateJsonEntity::getId);
                    FlowTemplateJsonEntity flowTemplateJsonEntity = flowTemplateJsonService.getOne(lambdaQueryWrapper);
                    FlowTemplateAllModel templateAllModel = flowTaskUtil.templateJson(flowTemplateJsonEntity.getId());
                    FlowMsgModel flowMsgModel = new FlowMsgModel();
                    if(CollUtil.isNotEmpty(flowTaskCirculateEntities)){
                        flowMsgModel.setCirculateList(flowTaskCirculateEntities);
                        flowMsgModel.setMessageFlag(Boolean.TRUE);
                    }

                    flowMsgModel.setStartNodeProperties(properties);
                    flowMsgModel.setCurrentNodeProperties(properties);
//                    flowMsgModel.setNodeList(taskNodeList);
                    List<FlowTaskOperatorEntity> operatorEntityList = new ArrayList<>();
//                        operatorEntityList.add(operator);
//                        flowMsgModel.setOperatorList(operatorEntityList);
                    flowMsgModel.setData(map);
//                    flowMsgModel.setFlowModel(flowModel);
                    FlowTaskDTO flowTask = new FlowTaskDTO();
                    flowTask.setCreatorUserId(applyUserId);
                    flowTask.setStatus(processStatus);
                    flowTask.setFullName(businessTitle);
                    flowMsgModel.setTaskEntity(flowTask);

                    FlowTaskNodeDTO flowTaskNodeDTO = new FlowTaskNodeDTO();
                    flowTaskNodeDTO.setTaskId(processInstanceId);
                    flowTaskNodeDTO.setTaskNodeId(historicTaskInstance.getId());
                    flowMsgModel.setTaskNodeEntity(flowTaskNodeDTO);
                    FlowModel flowModel  = new FlowModel();
                    flowModel.setUserInfo(UserProvider.getUser());
                    flowMsgModel.setFlowModel(flowModel);
                    flowMsgModel.setFlowTemplateAllModel(templateAllModel);
                    flowMsgModel.setTaskId(execution.getProcessInstanceId());
                    flowMsgModel.setTaskNodeId(historicTaskInstance.getId());
                    flowMsgUtil.message(flowMsgModel);

                }
                else if(FlowNodeTypeEnum.SWERVE_TASK.getType().equals(nodeType)){
                    UserProvider userProvider = SpringContextHolder.getBean(UserProvider.class);
                    UserService userService = SpringContextHolder.getBean(UserService.class);
                    ScriptEngine scriptEngine = SpringContextHolder.getBean(ScriptEngine.class);
                    RuntimeService runtimeService = SpringContextHolder.getBean(RuntimeService.class);
                    ManagementService managementService = SpringContextHolder.getBean(ManagementService.class);

                    String jumpTaskNode = properties.getSwerveNode();

                    //


                    Map<String, Object> transientVariables = execution.getTransientVariables();

                    ManualTask currentFlowElement = (ManualTask) execution.getCurrentFlowElement();
                    SequenceFlow sequenceFlow = currentFlowElement.getIncomingFlows().get(0);
                    String attributeValueByTaskDefinitionKey = getAttributeValueByTaskDefinitionKey(process, sequenceFlow.getId(), "");
                    Properties sequenceFlowProperties = JSONObject.parseObject(attributeValueByTaskDefinitionKey, new TypeReference<Properties>() {
                    });
                    String swerveConditionExpressionStr = sequenceFlowProperties.getSwerveConditionExpressionStr();
                    Boolean flag = managementService.executeCommand(new ExpressionCmd(execution.getProcessInstanceId(), swerveConditionExpressionStr, transientVariables));


                    if(flag){

                        runtimeService.createChangeActivityStateBuilder()
                                .processInstanceId(execution.getProcessInstanceId())
                                .moveActivityIdTo(execution.getCurrentActivityId(),jumpTaskNode)
                                .changeState();
                    }
                    else{
                        log.error("转向跳转节点节点条件不成立,自动往下流转");
                    }
                }
                else if(FlowNodeTypeEnum.DX.getType().equals(nodeType)){

                }
                else if(FlowNodeTypeEnum.WX.getType().equals(nodeType)){

                }
                else if(FlowNodeTypeEnum.DING.getType().equals(nodeType)){

                }
                else if(FlowNodeTypeEnum.SB.getType().equals(nodeType)){

                }
                else if(FlowNodeTypeEnum.JUMP_EX_TASK.getType().equals(nodeType)){
                    RuntimeService runtimeService = SpringContextHolder.getBean(RuntimeService.class);
                    String jumpTaskNode = properties.getSwerveNode();
                        runtimeService.createChangeActivityStateBuilder()
                                .processInstanceId(execution.getProcessInstanceId())
                                .moveActivityIdTo(execution.getCurrentActivityId(),jumpTaskNode)
                                .changeState();
                }
            }

        }
    }










    @Override
    public boolean isFailOnException() {
        return true;
    }

    @Override
    public boolean isFireOnTransactionLifecycleEvent() {
        return false;
    }

    @Override
    public String getOnTransaction() {
        return null;
    }


    private RepositoryService getRepositoryService() {
        return SpringContextHolder.getBean(RepositoryService.class);
    }



    /**
     * 处理传阅信息
     * @param flowTaskOperatorEntityList
     */
//    private void operateCirculateInfo(Map<String,String> map, List<FlowTaskCirculateEntity> flowTaskOperatorEntityList, String type,DelegateExecution delegateExecution){
//        String taskDefinitionKey = MapUtil.getStr(map, "taskDefinitionKey");
//        String taskName = MapUtil.getStr(map, "taskName");
//        String taskId = MapUtil.getStr(map, "taskId");
//        String processInstanceId = MapUtil.getStr(map, "processInstanceId");
//        FlowTaskCirculateEntity flowTask = new FlowTaskCirculateEntity();
//        flowTask.setId(RandomUtil.uuId());
//        flowTask.setObjectId(type);
//        flowTask.setNodeCode(taskDefinitionKey);
//        flowTask.setNodeName(taskName);
//        if(StringUtils.isNotBlank(taskId)){
//            flowTask.setTaskNodeId(taskId);
//        }
//        flowTask.setTaskId(processInstanceId);
//        flowTask.setCreatorTime(new Date());
//        Map<String, Object> variables = delegateExecution.getVariables();
//        flowTask.setEnCode(MapUtil.getStr(variables,BILL_CODE));
//        flowTask.setFullName(MapUtil.getStr(variables,BUSINESS_TITLE));
//        flowTask.setFlowId(MapUtil.getStr(variables,FLOW_ENGINE_ID));
//        flowTask.setFlowCategory(MapUtil.getStr(variables,PROCESS_CATEGORY));
//        flowTask.setUpdateTime(new Date());
//        flowTask.setCreateUserId(MapUtil.getStr(variables,APPLY_USER_ID));
//        flowTaskOperatorEntityList.add(flowTask);
//    }


    /**
     * 获取HttpServletRequest
     * @return
     */
    private static HttpServletRequest getRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        return request;
    }


    /**
     * 发送消息封装
     *
     * @param title       名称
     * @param type        类型
     * @param messageType 发送消息类型
     * @param userList    发送用户
     * @return
     */
    private SentMessageForm message(String title, int type, List<String> messageType, String processInstanceId, List<String> userList, String fullName) {
        SentMessageForm sentMessageForm = new SentMessageForm();
//        sentMessageForm.setSendType(messageType);
        Map<String, Object> message = new HashMap<>(16);
        message.put("type", type);
        message.put("id", processInstanceId);
        sentMessageForm.setContent(JsonUtilEx.getObjectToString(message));
        sentMessageForm.setTitle(fullName + title);
        sentMessageForm.setToUserIds(userList);
        Map<String, String> smsContent = new HashMap<>(16);
        this.message(fullName, title, smsContent);
//        sentMessageForm.setSmsContent(smsContent);
        return sentMessageForm;
    }

    /**
     * 短信模板
     *
     * @param title  标题
     * @param status 状态
     * @return
     */
    private void message(String title, String status, Map<String, String> msg) {
        Map<String, String> aliyun = new HashMap<>(16);
        aliyun.put("title", title);
        aliyun.put("status", status);
        msg.put("1", JsonUtil.getObjectToString(aliyun));
        msg.put("2", "2");
    }

}
